import { computed, ref, watch, watchEffect } from 'vue'
import { merge } from 'lodash-es'
import type { IResultRawTableItem } from '../type'
import usestore from '@/stores'
import { useFetch } from '@/composables/useFetch'
import { getContribution, getDrCluster, getOptimization, getRawData, getSampleCluster, getSensitivity, getSom, runCase } from '@/api/cases'
import { scatterBaseOptions } from '@/components/ui/chart/src/scatterOptions'
import { CHART_COLORS } from '@/components/ui/chart/src/color'
import { scatter3DBaseOptions } from '@/components/ui/chart/src/scatter3DOptions'
import { getQueryFromSearch, hvTransformArray } from '@/utils'

const { cases } = usestore()
const detailData = computed(() => cases.caseInfo?.jsonArgs ? JSON.parse(cases.caseInfo?.jsonArgs) : null)

export function useCaseResult(compareFlag?: boolean) {
  // 这些请求数据需要放在函数里，放在外面会覆盖(compare case的场景：同时触发相同接口，数据拿到后会同名覆盖)
  const { execute: runCaseExecute } = useFetch((parmas: any = {}) => runCase(parmas))
  const { data: dRClusterResult, loading: dRClsusterLoading, error: drError, execute: dRClusterExecute } = useFetch((parmas: any = {}) => getDrCluster(parmas))
  const { data: rawDataResult, loading: rawLoading, error: rawError, execute: rawDataExecute } = useFetch((parmas: any = {}) => getRawData(parmas))
  const { data: sampleDataResult, loading: sampleLoading, error: sampleError, execute: sampleClusterExecute } = useFetch((parmas: any = {}) => getSampleCluster(parmas))
  const { data: somResult, loading: somRawLoading, error: somError, execute: somResultExecute } = useFetch((parmas: any = {}) => getSom(parmas))
  const { data: sensitivityResult, loading: sensitiveLoading, error: sensitivityError, execute: sensitivityExecute } = useFetch((parmas: any = {}) => getSensitivity(parmas))
  const { data: optimizationResult, loading: optimizationLoading, error: optimizationError, execute: optimizationExecute } = useFetch((parmas: any = {}) => getOptimization(parmas))
  const { data: contributionResult, loading: contributionLoading, error: contributionError, execute: contributionExecute } = useFetch((parmas: any = {}) => getContribution(parmas))

  const queryData = getQueryFromSearch()

  async function onClickRunAction(caseId: string) {
    await runCaseExecute({ caseId: caseId || queryData.id })
  }

  function onClickRefreshAllAction(caseId?: string) {
    const parmas = { caseId: caseId || queryData.id }
    const fiveSteps = ['Caculation Result']
    const somStep = ['SOM']
    const senStep = ['Sensitivity analysis']
    const optimizeStep = ['Optimization']
    const contributionStep = ['Contribution']
    if (compareFlag)
      cases.currentStepNumber = 2

    switch (cases.currentStepNumber) {
      case 2:
        Promise.all([dRClusterExecute(parmas), rawDataExecute(parmas), sampleClusterExecute(parmas)]).then(() => {
          _handleRawTableData()
          _handleRawLineData()
          _handleScatter2DData()
          _handleScatter3DData()
        }).catch(() => {
          if (drError.value || rawError.value || sampleError.value)
            cases.updateCaseProcess(fiveSteps, 'error')
        })
        break
      case 3:
        Promise.all([somResultExecute(parmas)]).catch(() => {
          if (somError.value)
            cases.updateCaseProcess(somStep, 'error')
        })
        break
      case 4:
        Promise.all([sensitivityExecute(parmas)]).catch(() => {
          if (sensitivityError.value)
            cases.updateCaseProcess(senStep, 'error')
        })
        break
      case 5:
        Promise.all([optimizationExecute(parmas)]).catch(() => {
          if (optimizationError.value)
            cases.updateCaseProcess(optimizeStep, 'error')
        })
        break
      case 6:
        Promise.all([contributionExecute(parmas)]).catch(() => {
          if (contributionError.value)
            cases.updateCaseProcess(contributionStep, 'error')
        })
        break
    }
  }

  // Raw Table
  const tableData = ref([])
  const tableColumns = ref<IResultRawTableItem[]>([])
  function _handleRawTableData() {
    const rawTable = rawDataResult.value?.raw_data_table
    const columns = ['index'].concat(rawTable.columns)
    if (!rawTable) {
      tableData.value = tableColumns.value = []
      return
    }

    tableData.value = rawTable['dataset-records'].map((item: any, index: number) => {
      Object.keys(item).forEach((key: string) => {
        item[key] = (+item[key]).toFixed(3)
      })
      return { index: index + 1, ...item }
    })

    tableColumns.value = columns.map((item: string) => {
      return {
        dataIndex: item,
        title: item,
        align: 'center',
      }
    })
  }

  //  Raw Line
  const lineOptions = ref(scatterBaseOptions)
  const hasLineData = ref()
  const legendData = ref()
  function _handleRawLineData() {
    const { data: rawData, columns: legend } = rawDataResult.value?.raw_scatter_2d['dataset-split']
    legendData.value = legend

    const lineDatalist = hvTransformArray(rawData).map((item: any, index: number) => {
      return {
        type: 'line',
        name: legend[index],
        symbolSize: 0,
        symbol: 'circle',
        data: item,
        lineStyle: {
          width: 4,
        },
      }
    })
    hasLineData.value = lineDatalist.length > 0

    lineOptions.value = merge(
      {},
      scatterBaseOptions,
      {
        grid: { top: 100 },
        xAxis: {
          name: 'Samples',
          nameTextStyle: {
            padding: [30, 0, 0, 0], // 可以调整标题距离坐标轴的距离 [上，右，下，左]
          },
          type: 'category',
          // axisLabel: { intelvar: 0 }, // 设置横坐标全部显示，不间隔
          // show: false,
        },
        yAxis: {
          name: 'Values',
          nameTextStyle: {
            padding: [0, 30, 30, 0], // 可以调整标题距离坐标轴的距离 [上，右，下，左]
          },
          type: 'value',
          // splitLine: { show: false },
          boundaryGap: ['0.2', '0.2'],
        },
        // dataZoom: [
        //   {
        //     type: 'slider', // 缩放条
        //     start: 0, // 起始位置百分比
        //     end: 100, // 结束位置百分比
        //     bottom: 40,
        //   },
        //   {
        //     type: 'inside', // 内置缩放
        //     start: 0, // 起始位置百分比
        //     end: 100, // 结束位置百分比
        //   },
        // ],
        legend: { data: legend },
        series: lineDatalist,
      },
    )
  }
  const showAllLine = ref(true)
  function onClickToggleAllLine() {
    const selected: Record<string, boolean> = {}
    for (const item of legendData.value) {
      if (showAllLine.value)
        selected[item] = false
      else
        selected[item] = true
    }
    showAllLine.value = !showAllLine.value
    lineOptions.value.legend.selected = selected
  }

  // Scatter 2D
  const scatter2DXAxisValue = ref('')
  const scatter2DYAxisValue = ref('')
  const scatter2DSelectOptions = ref([])
  const scatter2DOptions = ref(scatterBaseOptions)
  function _handleScatter2DData() {
    cases.setClusterMax(dRClusterResult.value?.cluster_number || 1)
    const cluster_3d = dRClusterResult.value?.cluster_3d
    const cluster_2d = dRClusterResult.value?.cluster_2d
    const specialTwoD = detailData.value.DR.n_components < 3
    if (specialTwoD) {
      _setSpecialScatter2DChartOption(cluster_2d)
      return
    }
    if (!cluster_3d && !cluster_2d) {
      scatter2DSelectOptions.value = []
      scatter2DOptions.value = scatterBaseOptions
      return
    }

    const { dataset, encode } = cluster_3d
    scatter2DSelectOptions.value = dataset.dimensions.map((item: string) => {
      if (item === 'Label')
        return null
      return {
        label: item,
        value: item,
      }
    }).filter((item: any) => item)

    scatter2DXAxisValue.value = encode.x
    scatter2DYAxisValue.value = encode.y

    _setScatter2DChartOption(dataset)
  }
  function _setScatter2DChartOption(dataset: any) {
    const category = new Set()
    const mapField = Object.fromEntries(dataset.dimensions.map((item: any, index: number) => [item, index]))
    const data = dataset.source.map((item: any) => {
      if (item[dataset.dimensions.length - 1] !== 'Label')
        category.add(item[item.length - 1])
      return [
        item[mapField[scatter2DXAxisValue.value]],
        item[mapField[scatter2DYAxisValue.value]],
        item[dataset.dimensions.length - 1],
      ]
    })
    const categoryList = Array.from(category).sort((a: any, b: any) => a - b)

    scatter2DOptions.value = merge(
      {},
      scatterBaseOptions,
      {
        grid: {
          show: true, // border生效需要把show开启
          borderWidth: 1, // 设置边框线宽度
          borderColor: '#6e7079', // 设置边框线颜色
        },
        formatter(params: any) {
          return `<span style="font-weight: 600">Lable: ${params.data[2]}</span><br/> xAxis2D: ${params.data[0]}</br> yAxis2D: ${params.data[1]}}`
        },
        xAxis: {
          axisLine: { show: false },
        },
        yAxis: {
          axisLine: { show: false },
          boundaryGap: ['0.2', '0.2'],
        },
        visualMap: {
          type: 'piecewise',
          categories: categoryList,
          left: 'center',
          top: 10,
          orient: 'horizontal',
          hoverLink: false,
          inRange: {
            color: CHART_COLORS,
          },
        },
        series: [
          {
            data,
          },
        ],
      },
    )
  }

  function _setSpecialScatter2DChartOption(data: any) {
    scatter2DOptions.value = merge(
      {},
      scatterBaseOptions,
      {
        grid: {
          show: true, // border生效需要把show开启
          borderWidth: 1, // 设置边框线宽度
          borderColor: '#6e7079', // 设置边框线颜色
        },
        // formatter(params: any) {
        //   return `<span style="font-weight: 600">Lable: ${params.data[2]}</span><br/> xAxis2D: ${params.data[0]}</br> yAxis2D: ${params.data[1]}}`
        // },
        xAxis: {
          axisLine: { show: false },
        },
        yAxis: {
          axisLine: { show: false },
          boundaryGap: ['0.2', '0.2'],
        },
        legend: { data: data.serie_names },
        series: data.series,
      },
    )
  }

  watchEffect(() => {
    scatter2DOptions.value.xAxis.name = scatter2DXAxisValue.value
    scatter2DOptions.value.yAxis.name = scatter2DYAxisValue.value
  })
  watch([() => scatter2DXAxisValue.value, () => scatter2DYAxisValue.value], () => {
    _setScatter2DChartOption(dRClusterResult.value?.cluster_3d.dataset)
  })

  // Scatter 3D
  const scatter3DXAxisValue = ref('')
  const scatter3DYAxisValue = ref('')
  const scatter3DZAxisValue = ref('')
  const scatter3DSelectOptions = ref([])
  const scatter3DOptions = ref(scatter3DBaseOptions)
  function _handleScatter3DData() {
    const cluster_3d = dRClusterResult.value?.cluster_3d
    const { dataset, encode } = cluster_3d
    if (!cluster_3d) {
      scatter3DSelectOptions.value = []
      scatter3DOptions.value = scatter3DBaseOptions
      return
    }

    scatter3DSelectOptions.value = dataset.dimensions.map((item: string) => {
      if (item === 'Label')
        return null
      return {
        label: item,
        value: item,
      }
    }).filter((item: any) => item)

    scatter3DXAxisValue.value = encode.x
    scatter3DYAxisValue.value = encode.y
    scatter3DZAxisValue.value = encode.z

    _setScatter3DChartOption(dataset)
  }
  function _setScatter3DChartOption(dataset: any) {
    const category = new Set()
    const mapField = Object.fromEntries(dataset.dimensions.map((item: any, index: number) => [item, index]))
    const data = dataset.source.map((item: any) => {
    // 排除掉label名称-剩下的都是数据
      if (item[dataset.dimensions.length - 1] !== 'Label')
        category.add(item[dataset.dimensions.length - 1])
      return [
        item[mapField[scatter3DXAxisValue.value]],
        item[mapField[scatter3DYAxisValue.value]],
        item[mapField[scatter3DZAxisValue.value]],
      ].concat(Array.from({ length: dataset.dimensions.length - 3 }, () => item[dataset.dimensions.length - 1]))
    // 这里填充的label值是方便鼠标hover的时候可以显示其label值
    })

    const categoryList = Array.from(category).sort((a: any, b: any) => a - b)

    scatter3DOptions.value = merge(
      {},
      scatter3DBaseOptions,
      {
        tooltip: {},
        visualMap: {
          // category 映射
          type: 'piecewise',
          categories: categoryList,
          left: compareFlag ? 20 : 'center',
          top: compareFlag ? null : 10,
          orient: compareFlag ? 'vertical' : 'horizontal',
          hoverLink: false,
          inRange: {
            color: CHART_COLORS,
          },
          // bar 映射
          // max: Math.max(...[...dataMaxSet]),
          // min: 1,
          // dimension: 3,
          // inRange: {
          //   color: CHART_COLORS.slice(0, dataMaxSet.size),
          // },
        },
        xAxis3D: {
          name: scatter3DXAxisValue.value,
          type: 'value',
        },
        yAxis3D: {
          name: scatter3DYAxisValue.value,
          type: 'value',
        },
        zAxis3D: {
          name: scatter3DZAxisValue.value,
          type: 'value',
        },
        series: [
          {
            type: 'scatter3D',
            dimensions: dataset.dimensions,
            data,
          },
        ],
        formatter(params: any) {
          return `<span style="font-weight: 600">Lable: ${params.data[3]}</span><br/> xAxis3D: ${params.data[0]}</br> yAxis3D: ${params.data[1]} </br> zAxis3D: ${params.data[2]}`
        },
      },
    )
  }
  watchEffect(() => {
    scatter3DOptions.value.xAxis3D.name = scatter3DXAxisValue.value
    scatter3DOptions.value.yAxis3D.name = scatter3DYAxisValue.value
    scatter3DOptions.value.zAxis3D.name = scatter3DZAxisValue.value
  })
  watch([() => scatter3DXAxisValue.value, () => scatter3DYAxisValue.value, () => scatter3DZAxisValue.value], () => {
    _setScatter3DChartOption(dRClusterResult.value?.cluster_3d.dataset)
  })

  return {
    onClickRunAction,
    onClickRefreshAllAction,
    onClickToggleAllLine,
    dRClsusterLoading,
    rawLoading,
    sampleLoading,
    tableColumns,
    tableData,
    sampleDataResult,
    lineOptions,
    hasLineData,
    scatter2DOptions,
    scatter2DSelectOptions,
    scatter2DXAxisValue,
    scatter2DYAxisValue,
    scatter3DOptions,
    scatter3DSelectOptions,
    scatter3DXAxisValue,
    scatter3DYAxisValue,
    scatter3DZAxisValue,

    somResult,
    somRawLoading,
    somError,
    sensitivityResult,
    sensitiveLoading,
    sensitivityError,
    optimizationResult,
    optimizationLoading,
    optimizationError,
    contributionResult,
    contributionLoading,
    contributionError,
  }
}
